home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 1 / CU Amiga Magazine CD-ROM Special Edition (1995)(EMAP Images)(GB)[Issue 1995-11].iso / Aminet / comm / tcp / ATCP_sdk_40_gc.lha / AmiTCP-4.0-gcc / src / netlib / rcmd.c < prev    next >
C/C++ Source or Header  |  1995-04-02  |  9KB  |  295 lines

  1. static const char *RCS = "$Id: rcmd.c,v 4.2 1994/09/29 23:09:02 jraja Exp $";
  2. /*
  3.  *    rcmd.c - rcmd() for AmiTCP/IP and usergroup.library
  4.  *
  5.  *    Copyright © 1994 AmiTCP/IP Group,
  6.  *             Network Solutions Development Inc.
  7.  *             All rights reserved.
  8.  */
  9.  
  10. /*
  11.  * Copyright (c) 1983 Regents of the University of California.
  12.  * All rights reserved.
  13.  *
  14.  * Redistribution and use in source and binary forms, with or without
  15.  * modification, are permitted provided that the following conditions
  16.  * are met:
  17.  * 1. Redistributions of source code must retain the above copyright
  18.  *    notice, this list of conditions and the following disclaimer.
  19.  * 2. Redistributions in binary form must reproduce the above copyright
  20.  *    notice, this list of conditions and the following disclaimer in the
  21.  *    documentation and/or other materials provided with the distribution.
  22.  * 3. All advertising materials mentioning features or use of this software
  23.  *    must display the following acknowledgement:
  24.  *    This product includes software developed by the University of
  25.  *    California, Berkeley and its contributors.
  26.  * 4. Neither the name of the University nor the names of its contributors
  27.  *    may be used to endorse or promote products derived from this software
  28.  *    without specific prior written permission.
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  31.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  34.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  35.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  36.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  37.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  38.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  39.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  40.  * SUCH DAMAGE.
  41.  */
  42.  
  43.  
  44. #include <proto/socket.h>
  45. #include <clib/exec_protos.h>
  46.  
  47. #include <sys/param.h>
  48. #include <sys/ioctl.h>
  49. #include <sys/socket.h>
  50. #include <sys/stat.h>
  51. #include <netinet/in.h>
  52. #if 0
  53. #include <signal.h>
  54. #endif
  55. #include <fcntl.h>
  56. #include <netdb.h>
  57. #include <pwd.h>
  58. #include <errno.h>
  59. #include <stdio.h>
  60. #include <ctype.h>
  61.  
  62. #include <unistd.h>
  63. #include <string.h>
  64.  
  65. /****** net.lib/rcmd *********************************************************
  66.  
  67.     NAME
  68.     rcmd, rresvport - routines for returning a stream to a remote command
  69.  
  70.     SYNOPSIS
  71.     #include <clib/socket_protos.h>
  72.  
  73.     int rcmd(char **ahost, int inport, const char *locuser,
  74.          const char *remuser, const char *cmd, int *fd2p);
  75.  
  76.     int rresvport(int *port);
  77.  
  78.     FUNCTION
  79.     The rcmd() function is used by the super-user to execute a command on
  80.     a remote machine using an authentication scheme based on reserved port
  81.     numbers.  The rresvport() function returns a descriptor to a socket
  82.     with an address in the privileged port space.  Both functions are
  83.     present in the same file and are used by the rsh command (among
  84.     others).
  85.  
  86.     The rcmd() function looks up the host *ahost using gethostbyname(),
  87.     returning -1 if the host does not exist.  Otherwise *ahost is set to
  88.     the standard name of the host and a connection is established to a
  89.     server residing at the well-known Internet port inport.
  90.  
  91.     If the connection succeeds, a socket in the Internet domain of type
  92.     SOCK_STREAM is returned to the caller, and given to the remote command
  93.     as stdin and stdout. If fd2p is non-zero, then an auxiliary channel to
  94.     a control process will be set up, and a descriptor for it will be
  95.     placed in *fd2p. The control process will return diagnostic output
  96.     from the command (unit 2) on this channel, and will also accept bytes
  97.     on this channel as being UNIX signal numbers, to be forwarded to the
  98.     process group of the command.  If fd2p is 0, then the stderr (unit 2
  99.     of the remote command) will be made the same as the stdout and no
  100.     provision is made for sending arbitrary signals to the remote process,
  101.     although you may be able to get its attention by using out-of-band
  102.     data.
  103.  
  104.     The protocol is described in detail in netutil/rshd.
  105.  
  106.     The rresvport() function is used to obtain a socket with a privileged
  107.     address bound to it.  This socket is suitable for use by rcmd() and
  108.     several other functions.  Privileged Internet ports are those in the
  109.     range 0 to 1023.  Only the super-user is allowed to bind an address of
  110.     this sort to a socket.
  111.  
  112.     DIAGNOSTICS
  113.     The rcmd() function returns a valid socket descriptor on success.  It
  114.     returns -1 on error and prints a diagnostic message on the standard
  115.     error.
  116.  
  117.     The rresvport() function returns a valid, bound socket descriptor on
  118.     success.  It returns -1 on error with the global value errno set
  119.     according to the reason for failure.  The error code EAGAIN is
  120.     overloaded to mean `All network ports in use.'
  121.  
  122.     SEE ALSO
  123.     netutil/rlogin,  netutil/rsh,  rexec(),  netutil/rexecd,
  124.     netutil/rlogind, netutil/rshd
  125.  
  126. ******************************************************************************
  127. */
  128.  
  129. #include <clib/netlib_protos.h>
  130.  
  131. int
  132. rcmd(char **ahost,
  133.      int rport,
  134.      const char *locuser,
  135.      const char *remuser,
  136.      const char *cmd,
  137.      int *fd2p)         /* Socket for stderr  */
  138. {
  139.   int s, timo = 1;
  140.   pid_t pid;
  141.   struct sockaddr_in sin, from;
  142.   char c;
  143.   int lport = IPPORT_RESERVED - 1;
  144.   struct hostent *hp;
  145.   fd_set reads;
  146.  
  147.   pid = getpid();
  148.   hp = gethostbyname(*ahost);
  149.   if (hp == 0) {
  150.     herror(*ahost);
  151.     errno = EADDRNOTAVAIL;
  152.     return (-1);
  153.   }
  154.   *ahost = hp->h_name;
  155.  
  156.   for (;;) {
  157.     s = rresvport(&lport);
  158.     if (s < 0) {
  159.       errno == EAGAIN ?
  160.     fprintf(stderr, "socket: All ports in use\n")
  161.       : perror("rcmd: socket");
  162.       return (-1);
  163.     }
  164.     ioctl(s, FIOSETOWN, (caddr_t)&pid);
  165.     sin.sin_len = sizeof(sin);
  166.     sin.sin_family = hp->h_addrtype;
  167.     bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
  168.     sin.sin_port = rport;
  169.     if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
  170.       break;
  171.     (void) close(s);
  172.     if (errno == EADDRINUSE) {
  173.       lport--;
  174.       continue;
  175.     }
  176.     if (errno == ECONNREFUSED && timo <= 16) {
  177.       sleep(timo);
  178.       timo *= 2;
  179.       continue;
  180.     }
  181.     if (hp->h_addr_list[1] != NULL) {
  182.       int oerrno = errno;
  183.  
  184.       fprintf(stderr, "connect to address %s: ", inet_ntoa(sin.sin_addr));
  185.       errno = oerrno;
  186.       perror("");
  187.       hp->h_addr_list++;
  188.       bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
  189.       fprintf(stderr, "Trying %s...\n", inet_ntoa(sin.sin_addr));
  190.       continue;
  191.     }
  192.     perror(hp->h_name);
  193.     return (-1);
  194.   }
  195.  
  196.   lport--;
  197.   if (fd2p == 0) {
  198.     send(s, "", 1, 0);
  199.     lport = 0;
  200.   } else {
  201.     char num[8];
  202.     long s2 = rresvport(&lport), s3;
  203.     long len = sizeof (from);
  204.  
  205.     if (s2 < 0)
  206.       goto bad;
  207.     listen(s2, 1);
  208.     (void) sprintf(num, "%ld", lport);
  209.     if (send(s, num, strlen(num)+1, 0) != strlen(num)+1) {
  210.       perror("send: setting up stderr");
  211.       (void) close(s2);
  212.       goto bad;
  213.     }
  214.     FD_ZERO(&reads);
  215.     FD_SET(s, &reads);
  216.     FD_SET(s2, &reads);
  217.     errno = 0;
  218.     if (WaitSelect(((s > s2) ? s : s2) + 1,
  219.            &reads, 0, 0, 0,NULL) < 1 || !FD_ISSET(s2, &reads)) {
  220.       errno != 0 ?
  221.       perror("select: setting up stderr")
  222.       :
  223.       fprintf(stderr, "select: protocol failure in circuit setup.\n");
  224.       (void) close(s2);
  225.       goto bad;
  226.     }
  227.     s3 = accept(s2, (struct sockaddr *)&from, &len);
  228.     (void) close(s2);
  229.     if (s3 < 0) {
  230.       perror("accept");
  231.       lport = 0;
  232.       goto bad;
  233.     }
  234.     *fd2p = s3;
  235.     from.sin_port = ntohs((u_short)from.sin_port);
  236.     if (from.sin_family != AF_INET ||
  237.     from.sin_port >= IPPORT_RESERVED ||
  238.     from.sin_port < IPPORT_RESERVED / 2) {
  239.       fprintf(stderr, "socket: protocol failure in circuit setup.\n");
  240.       goto bad2;
  241.     }
  242.   }
  243.   (void) send(s, locuser, strlen(locuser) + 1, 0);
  244.   (void) send(s, remuser, strlen(remuser) + 1, 0);
  245.   (void) send(s, cmd, strlen(cmd) + 1, 0);
  246.   if (recv(s, &c, 1, 0) != 1) {
  247.     perror(*ahost);
  248.     goto bad2;
  249.   }
  250.   if (c != 0) {
  251.     while (recv(s, &c, 1, 0) == 1) {
  252.       (void) fputc(c, stderr);
  253.       if (c == '\n')
  254.     break;
  255.     }
  256.     goto bad2;
  257.   }
  258.  
  259.   return (s);
  260.  bad2:
  261.   if (lport)
  262.     (void) close(*fd2p);
  263.  bad:
  264.   (void) close(s);
  265.   return (-1);
  266. }
  267.  
  268. int rresvport(int *alport)
  269. {
  270.   struct sockaddr_in sin;
  271.   int s;
  272.  
  273.   sin.sin_len = sizeof(sin);
  274.   sin.sin_family = AF_INET;
  275.   sin.sin_addr.s_addr = INADDR_ANY;
  276.   s = socket(AF_INET, SOCK_STREAM, 0);
  277.   if (s < 0)
  278.     return (-1);
  279.   for (;;) {
  280.     sin.sin_port = htons((u_short)*alport);
  281.     if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
  282.       return (s);
  283.     if (errno != EADDRINUSE) {
  284.       (void) close(s);
  285.       return (-1);
  286.     }
  287.     (*alport)--;
  288.     if (*alport == IPPORT_RESERVED/2) {
  289.       (void) close(s);
  290.       errno = EAGAIN;        /* close */
  291.       return (-1);
  292.     }
  293.   }
  294. }
  295.